import { NodePool, Prefab, instantiate, Node } from 'cc';

export class PoolManager {
    private static _instance: PoolManager;
    public static get instance(): PoolManager {
        if (!this._instance) {
            this._instance = new PoolManager();
        }
        return this._instance;
    }

    private constructor() { }

    private pools: Map<string, NodePool> = new Map();

    public getPool(name: string, prefab: Prefab): NodePool {
        if (!this.pools.has(name)) {
            this.pools.set(name, new NodePool());
        }
        return this.pools.get(name)!;
    }

    public getNode(name: string, prefab: Prefab): Node {
        const pool = this.getPool(name, prefab);
        return pool.size() > 0 ? pool.get() : instantiate(prefab);
    }

    public putNode(name: string, node: Node): void {
        const pool = this.pools.get(name);
        if (pool) {
            pool.put(node);
        } else {
            node.destroy();
        }
    }

    /**
     * 清空指定对象池
     * @example
     * PoolManager.instance.clearPool('enemy');
     */
    public clearPool(name: string): void {
        const pool = this.pools.get(name);
        if (pool) {
            pool.clear();
        }
    }

    /**
     * 销毁指定对象池
     * @example
     * PoolManager.instance.destroyPool('enemy');
     */
    public destroyPool(name: string): void {
        const pool = this.pools.get(name);
        if (pool) {
            pool.clear();
            this.pools.delete(name);
        }
    }

    // ================== 泛型对象池扩展 ==================
    private genericPools: Map<string, any[]> = new Map();
    private genericPoolLimits: Map<string, number> = new Map();
    private genericPoolLastUsed: Map<string, number> = new Map();

    /**
     * 获取通用对象池中的对象
     * @param name 池名
     * @param createFn 创建新对象的方法
     */
    public getGeneric<T>(name: string, createFn: () => T): T {
        this.genericPoolLastUsed.set(name, Date.now());
        if (!this.genericPools.has(name)) this.genericPools.set(name, []);
        const pool = this.genericPools.get(name)!;
        return pool.length > 0 ? pool.pop() : createFn();
    }

    /**
     * 批量获取通用对象池中的对象
     * @param name 池名
     * @param count 数量
     * @param createFn 创建新对象的方法
     */
    public getGenericMany<T>(name: string, count: number, createFn: () => T): T[] {
        this.genericPoolLastUsed.set(name, Date.now());
        if (!this.genericPools.has(name)) this.genericPools.set(name, []);
        const pool = this.genericPools.get(name)!;
        const arr: T[] = [];
        for (let i = 0; i < count; i++) {
            arr.push(pool.length > 0 ? pool.pop() : createFn());
        }
        return arr;
    }

    /**
     * 回收通用对象到对象池
     * @param name 池名
     * @param obj 对象
     * @param resetFn 可选重置方法
     */
    public putGeneric<T>(name: string, obj: T, resetFn?: (o: T) => void) {
        this.genericPoolLastUsed.set(name, Date.now());
        if (!this.genericPools.has(name)) this.genericPools.set(name, []);
        if (resetFn) resetFn(obj);
        const pool = this.genericPools.get(name)!;
        const limit = this.genericPoolLimits.get(name);
        if (limit === undefined || pool.length < limit) {
            pool.push(obj);
        }
        // 超出容量则丢弃（可自定义销毁逻辑）
    }

    /**
     * 批量回收通用对象到对象池
     * @param name 池名
     * @param objs 对象数组
     * @param resetFn 可选重置方法
     */
    public putGenericMany<T>(name: string, objs: T[], resetFn?: (o: T) => void) {
        this.genericPoolLastUsed.set(name, Date.now());
        if (!this.genericPools.has(name)) this.genericPools.set(name, []);
        const pool = this.genericPools.get(name)!;
        const limit = this.genericPoolLimits.get(name);
        if (resetFn) objs.forEach(resetFn);
        if (limit === undefined || pool.length + objs.length <= limit) {
            pool.push(...objs);
        } else if (limit !== undefined) {
            // 只放入能容纳的数量
            const canPush = Math.max(0, limit - pool.length);
            if (canPush > 0) pool.push(...objs.slice(0, canPush));
            // 其余丢弃
        }
    }

    /**
     * 设置通用对象池容量上限
     * @param name 池名
     * @param limit 最大容量
     */
    public setGenericPoolLimit(name: string, limit: number) {
        this.genericPoolLimits.set(name, limit);
    }

    /**
     * 清空通用对象池
     */
    public clearGenericPool(name: string): void {
        if (this.genericPools.has(name)) {
            this.genericPools.get(name)!.length = 0;
        }
    }

    /**
     * 销毁通用对象池
     */
    public destroyGenericPool(name: string): void {
        this.genericPools.delete(name);
        this.genericPoolLimits.delete(name);
        this.genericPoolLastUsed.delete(name);
    }

    /**
     * 自动清理长时间未使用的通用对象池
     * @param maxIdleMs 最大空闲毫秒数，默认1分钟
     */
    public autoClearUnusedGenericPools(maxIdleMs: number = 60000) {
        const now = Date.now();
        for (const [name, last] of this.genericPoolLastUsed.entries()) {
            if (now - last > maxIdleMs) {
                this.clearGenericPool(name);
                this.genericPoolLastUsed.delete(name);
            }
        }
    }
} 